/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/

/*  SimpleSockets - a simple Linux/Windows library for using TCP & UDP sockets.
 *  2007 (c) Renne Nissinen <rennex@iki.fi>
 */


#ifndef __SIMPLESOCKETS_H__
#define __SIMPLESOCKETS_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>
#include <string.h>


#ifdef _WIN32

    #include <Winsock2.h>

#else

    #include <unistd.h>
    #include <sys/socket.h>
    #include <sys/time.h>
    #include <netdb.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>

    // Winsock's SOCKET type is unsigned, so they use these constants (~0 and -1, respectively)
    #define INVALID_SOCKET (-1)
    #define SOCKET_ERROR (-1)
    typedef int SOCKET;

    #define closesocket(s) close(s)

#endif


/* Initializes the TCP/IP stack (needed on Windows).

   Returns 1 on success, 0 on failure.
*/
int ss_init(void);

/* Deinitializes the TCP/IP stack. */
void ss_deinit(void);


/* Initializes the struct sockaddr_in pointed to by addr. Sets the
   family to AF_INET, converts the port number and resolves the hostname
   (unless host is NULL, in which case sin_addr is set to INADDR_ANY).
   
   Returns 1 on success, or 0 if the hostname was not found.
*/
int ss_createsockaddr(struct sockaddr_in *addr, const char *host, int port);


/* Performs a DNS lookup for the given hostname. If successful,
   saves the IP address into the struct in_addr pointed to by addr.

   Returns 1 if successful, otherwise 0.
*/
int ss_lookup(const char *host, struct in_addr *addr);


/* Creates a TCP socket and connects it to the host & port.

   Returns the socket, or INVALID_SOCKET on error.
*/
SOCKET ss_connect(const char *host, int port);


/* Creates a listening TCP socket and binds it to the given port.
   Call ss_accept() to accept incoming connections.

   Returns the socket, or INVALID_SOCKET on error.
*/
SOCKET ss_listen(int port);


/* Accepts an incoming TCP connection on the socket (created with ss_listen()).
   Fills the address of the connecting entity to the supplied struct
   sockaddr_in (the pointer must not be NULL).

   Returns a new socket associated with the established connection, or
   INVALID_SOCKET on error.
*/
SOCKET ss_accept(SOCKET sock, struct sockaddr_in *peeraddr);


/* Sends the given data on the TCP socket - looping until everything is sent.

   Returns 1 on success, 0 on failure (connection broken).
*/
int ss_send(SOCKET sock, const void *message, int msglen);

/* Receives data from the TCP socket into a buffer, up to a maximum of
   maxlen bytes.
   
   Returns the number of bytes received, or -1 on error (0 when the peer
   has shut down the connection).
*/
int ss_receive(SOCKET sock, void *buffer, int maxlen);


/* Creates a UDP socket and binds it to the given port.

   Returns the socket, or INVALID_SOCKET on error.
*/
SOCKET ss_udpsocket(int port);


/* Sends a UDP datagram from the socket to the given destination.

   Returns the number of bytes sent, or -1 on error.
*/
int ss_udpsend(SOCKET sock, const struct sockaddr_in *dest, const void *message, int msglen);


/* Receives a UDP datagram from the socket into the buffer, and fills
   the sender's address to the struct sockaddr_in (the pointer may be NULL).
   If the buffer isn't large enough for the datagram, the excess bytes may be
   discarded.

   Returns the number of bytes received, or -1 on error.
*/
int ss_udpreceive(SOCKET sock, struct sockaddr_in *from, void *buffer, int maxlen);

#ifdef __cplusplus
}
#endif

#endif
